# coding=utf-8
from phosphorusScripts.common.shared import INTERACTIVE_OPTION_TYPES, MODIFIABLE_OPTION_TYPES, VALUE_CHECK_MAP


class ConfigManager(object):

    def __init__(self):
        self._configs = []
        """:type: list[str]"""
        self._sequenceMapping = {}
        """:type: dict[str, list[str]]"""
        self._contentMapping = {}
        """:type: dict[str, dict[str, dict]]"""
        self._operatorMapping = {}
        """:type: dict[str, dict[str, bool]]"""
        self._callbackMapping = {}
        """:type: dict[str, dict[str, function]]"""

    def register(self, namespace, builtDict):
        """
        :type namespace: str
        :type builtDict: dict
        :rtype: bool
        """
        if namespace in self._configs:
            return False
        self._configs.append(namespace)
        self._sequenceMapping[namespace] = builtDict['sequence']
        self._contentMapping[namespace] = builtDict['content']
        self._operatorMapping[namespace] = builtDict['operator']
        self._callbackMapping[namespace] = builtDict['callback']
        return True

    def getScreenData(self):
        """
        :rtype: dict
        """
        return {
            'configs': self._configs,
            'sequenceMapping': self._sequenceMapping,
            'contentMapping': self._contentMapping,
            'operatorMapping': self._operatorMapping,
        }

    def isModifiableOption(self, namespace, key):
        """
        :type namespace: str
        :type key: str
        :rtype: bool
        """
        return (namespace in self._contentMapping
                and key in self._contentMapping[namespace]
                and self._contentMapping[namespace][key]['type'] in MODIFIABLE_OPTION_TYPES)

    def isInteractiveOption(self, namespace, key):
        """
        :type namespace: str
        :type key: str
        :rtype: bool
        """
        return (namespace in self._contentMapping
                and key in self._contentMapping[namespace]
                and self._contentMapping[namespace][key]['type'] in INTERACTIVE_OPTION_TYPES)

    def getModifiableOptionCurrent(self, namespace, key):
        """
        :type namespace: str
        :type key: str
        :rtype: bool|str|int|float
        """
        return self._contentMapping[namespace][key]['current']

    def setModifiableOptionCurrent(self, namespace, key, value):
        """
        :type namespace: str
        :type key: str
        :type value: bool|str|int|float
        :rtype: bool
        """
        option = self._contentMapping[namespace][key]
        if not VALUE_CHECK_MAP[option['type']](value, option):
            return False
        option['current'] = value
        return True

    def getOptionOperator(self, namespace, key):
        """
        :type namespace: str
        :type key: str
        :rtype: bool
        """
        return self._operatorMapping[namespace].get(key, False)

    def getOptionCallback(self, namespace, key):
        """
        :type namespace: str
        :type key: str
        :rtype: function|None
        """
        return self._callbackMapping[namespace].get(key)
